home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 December / 2004-12 CHIP.iso / CHIP / Porady / Srodowisko PHP-MySQL / ACTIVESTATE PERL ADD-ON / PERL_add-on.exe / {app} / perl / bin / search.bat < prev    next >
DOS Batch File  |  2004-06-01  |  57KB  |  1,888 lines

  1. @rem = '--*-Perl-*--
  2. @echo off
  3. if "%OS%" == "Windows_NT" goto WinNT
  4. perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9
  5. goto endofperl
  6. :WinNT
  7. perl -x -S %0 %*
  8. if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl
  9. if %errorlevel% == 9009 echo You do not have Perl in your PATH.
  10. if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul
  11. goto endofperl
  12. @rem ';
  13. #!/usr/local/bin/perl -w
  14. #line 15
  15. 'di';
  16. 'ig00';
  17. ##############################################################################
  18. ##
  19. ## search
  20. ##
  21. ## Jeffrey Friedl (jfriedl@omron.co.jp), Dec 1994.
  22. ## Copyright 19.... ah hell, just take it.
  23. ##
  24. ## BLURB:
  25. ## A combo of find and grep -- more or less do a 'grep' on a whole
  26. ## directory tree. Fast, with lots of options. Much more powerful than
  27. ## the simple "find ... | xargs grep ....". Has a full man page.
  28. ## Powerfully customizable.
  29. ##
  30. ## This file is big, but mostly comments and man page.
  31. ##
  32. ## See man page for usage info.
  33. ## Return value: 2=error, 1=nothing found, 0=something found.
  34. ##
  35.  
  36. $version = "950918.5";
  37. ##
  38. ## "950918.5";
  39. ##    Changed all 'sysread' to 'read' because Linux perl's don't seem
  40. ##    to like sysread()
  41. ##
  42. ## "941227.4";
  43. ##    Added -n, -u
  44. ##
  45. ## "941222.3"
  46. ##      Added -nice (due to Lionel Cons <Lionel.Cons@cern.ch>)
  47. ##    Removed any leading "./" from name.
  48. ##      Added default flags for ~/.search, including TTY, -nice, -list, etc.
  49. ##    Program name now has path removed when printed in diagnostics.
  50. ##    Added simple tilde-expansion to -dir arg.
  51. ##    Added -dskip, etc. Fixed -iregex bug.
  52. ##    Changed -dir to be additive, adding -ddir.
  53. ##    Now screen out devices, pipes, and sockets.
  54. ##    More tidying and lots of expanding of the man page
  55. ##
  56. ##
  57. ## "941217.2";
  58. ##    initial release.
  59.  
  60. $stripped=0;
  61.  
  62. &init;
  63. if (exists $ENV{'HOME'}) {
  64.     $rc_file = join('/', $ENV{'HOME'}, ".search");
  65. }
  66. else {
  67.     $rc_file = "";
  68. }
  69.  
  70. &check_args;
  71.  
  72. ## Make sure we've got a regex.
  73. ## Don't need one if -find or -showrc was specified.
  74. $!=2, die "expecting regex arguments.\n"
  75.     if $FIND_ONLY == 0 && $showrc == 0 && @ARGV == 0;
  76.  
  77. &prepare_to_search($rc_file);
  78.  
  79. &import_program if !defined &dodir; ## BIG key to speed.
  80.  
  81. ## do search while there are directories to be done.
  82. &dodir(shift(@todo)) while @todo;
  83.  
  84. &clear_message if $VERBOSE && $STDERR_IS_TTY;
  85. exit($retval);
  86. ###############################################################################
  87.  
  88. sub init
  89. {
  90.   ## initialize variables that might be reset by command-line args
  91.   $DOREP=0;         ## set true by -dorep (redo multi-hardlink files)
  92.   $DOREP=1 if $^O eq 'MSWin32';
  93.   $DO_SORT=0;           ## set by -sort (sort files in a dir before checking)
  94.   $FIND_ONLY=0;         ## set by -find (don't search files)
  95.   $LIST_ONLY=0;        ## set true by -l (list filenames only)
  96.   $NEWER=0;             ## set by -newer, "-mtime -###"
  97.   $NICE=0;              ## set by -nice (print human-readable output)
  98.   $NOLINKS=0;         ## set true by -nolinks (don't follow symlinks)
  99.   $OLDER=0;             ## set by -older, "-mtime  ###"
  100.   $PREPEND_FILENAME=1;  ## set false by -h (don't prefix lines with filename)
  101.   $REPORT_LINENUM=0;    ## set true by -n (show line numbers)
  102.   $VERBOSE=0;        ## set to a value by -v, -vv, etc. (verbose messages)
  103.   $WHY=0;        ## set true by -why, -vvv+ (report why skipped)
  104.   $XDEV=0;        ## set true by -xdev (stay on one filesystem)
  105.   $all=0;        ## set true by -all (don't skip many kinds of files)
  106.   $iflag = '';        ## set to 'i' by -i (ignore case);
  107.   $norc=0;              ## set by -norc (don't load rc file)
  108.   $showrc=0;            ## set by -showrc (show what happens with rc file)
  109.   $underlineOK=0;       ## set true by -u (watch for underline stuff)
  110.   $words=0;             ## set true by -w (match whole-words only)
  111.   $DELAY=0;        ## inter-file delay (seconds)
  112.   $retval=1;            ## will set to 0 if we find anything.
  113.  
  114.   ## various elements of stat() that we might access
  115.   $STAT_DEV   = 1;
  116.   $STAT_INODE = 2;
  117.   $STAT_MTIME = 9;
  118.  
  119.   $VV_PRINT_COUNT = 50;  ## with -vv, print every VV_PRINT_COUNT files, or...
  120.   $VV_SIZE = 1024*1024;  ## ...every VV_SIZE bytes searched
  121.   $vv_print = $vv_size = 0; ## running totals.
  122.  
  123.   ## set default options, in case the rc file wants them
  124.   $opt{'TTY'}= 1 if -t STDOUT;
  125.   
  126.   ## want to know this for debugging message stuff
  127.   $STDERR_IS_TTY = -t STDERR ? 1 : 0;
  128.   $STDERR_SCREWS_STDOUT = ($STDERR_IS_TTY && -t STDOUT) ? 1 : 0;
  129.  
  130.   $0 =~ s,.*/,,;  ## clean up $0 for any diagnostics we'll be printing.
  131. }
  132.  
  133. ##
  134. ## Check arguments.
  135. ##
  136. sub check_args
  137. {
  138.   while (@ARGV && $ARGV[0] =~ m/^-/)
  139.   {
  140.       $arg = shift(@ARGV);
  141.  
  142.       if ($arg eq '-version' || ($VERBOSE && $arg eq '-help')) {
  143.       print qq/Jeffrey's file search, version "$version".\n/;
  144.       exit(0) unless $arg eq '-help';
  145.       }
  146.       if ($arg eq '-help') {
  147.       print <<INLINE_LITERAL_TEXT;
  148. usage: $0 [options] [-e] [PerlRegex ....]
  149. OPTIONS TELLING *WHERE* TO SEARCH:
  150.   -dir DIR       start search at the named directory (default is current dir).
  151.   -xdev          stay on starting file system.
  152.   -sort          sort the files in each directory before processing.
  153.   -nolinks       don't follow symbolic links.
  154. OPTIONS TELLING WHICH FILES TO EVEN CONSIDER:
  155.   -mtime #       consider files modified > # days ago (-# for < # days old)
  156.   -newer FILE    consider files modified more recently than FILE (also -older)
  157.   -name GLOB     consider files whose name matches pattern (also -regex).
  158.   -skip GLOB     opposite of -name: identifies files to not consider.
  159.   -path GLOB     like -name, but for files whose whole path is described.
  160.   -dpath/-dregex/-dskip versions for selecting or pruning directories.
  161.   -all           don't skip any files marked to be skipped by the startup file.
  162.   -x<SPECIAL>    (see manual, and/or try -showrc).
  163.   -why           report why a file isn't checked (also implied by -vvvv).
  164. OPTIONS TELLING WHAT TO DO WITH FILES THAT WILL BE CONSIDERED:
  165.   -f  | -find    just list files (PerlRegex ignored). Default is to grep them.
  166.   -ff | -ffind   Does a faster -find (implies -find -all -dorep)
  167. OPTIONS CONTROLLING HOW THE SEARCH IS DONE (AND WHAT IS PRINTED):
  168.   -l | -list     only list files with matches, not the lines themselves.
  169.   -nice | -nnice print more "human readable" output.
  170.   -n             prefix each output line with its line number in the file.
  171.   -h             don't prefix output lines with file name.
  172.   -u             also look "inside" manpage-style underlined text
  173.   -i             do case-insensitive searching.
  174.   -w             match words only (as defined by perl's \\b).
  175. OTHER OPTIONS:
  176.   -v, -vv, -vvv  various levels of message verbosity.
  177.   -e             end of options (in case a regex looks like an option).
  178.   -showrc        show what the rc file sets, then exit.
  179.   -norc          don't load the rc file.
  180.   -dorep         check files with multiple hard links multiple times.
  181. INLINE_LITERAL_TEXT
  182.     print "Use -v -help for more verbose help.\n" unless $VERBOSE;
  183.     print "This script file is also a man page.\n" unless $stripped;
  184.     print <<INLINE_LITERAL_TEXT if $VERBOSE;
  185.  
  186. If -f (or -find) given, PerlRegex is optional and ignored.
  187. Otherwise, will search for files with lines matching any of the given regexes.
  188.  
  189. Combining things like -name and -mtime implies boolean AND.
  190. However, duplicating things (such as -name '*.c' -name '*.txt') implies OR.
  191.  
  192. -mtime may be given floating point (i.e. 1.5 is a day and a half).
  193. -iskip/-idskip/-ipath/... etc are case-insensitive versions.
  194.  
  195. If any letter in -newer/-older is upper case, "or equal" is
  196. inserted into the test.
  197.  
  198. You can always find the latest version on the World Wide Web in
  199.    http://www.wg.omron.co.jp/~jfriedl/perl/
  200. INLINE_LITERAL_TEXT
  201.       exit(0);
  202.       }
  203.       $DOREP=1,             next if $arg eq '-dorep';   ## do repeats
  204.       $DO_SORT=1,           next if $arg eq '-sort';    ## sort files
  205.       $NOLINKS=1,           next if $arg eq '-nolinks'; ## no sym. links
  206.       $PREPEND_FILENAME=0,  next if $arg eq '-h';       ## no filename prefix
  207.       $REPORT_LINENUM=1,    next if $arg eq '-n';       ## show line numbers
  208.       $WHY=1,               next if $arg eq '-why';     ## tell why skipped
  209.       $XDEV=1,              next if $arg eq '-xdev';    ## don't leave F.S.
  210.       $all=1,$opt{'-all'}=1,next if $arg eq '-all';     ## don't skip *.Z, etc
  211.       $iflag='i',           next if $arg eq '-i';       ## ignore case
  212.       $norc=1,              next if $arg eq '-norc';    ## don't load rc file
  213.       $showrc=1,            next if $arg eq '-showrc';  ## show rc file
  214.       $underlineOK=1,       next if $arg eq '-u';       ## look throuh underln.
  215.       $words=1,             next if $arg eq '-w';       ## match "words" only
  216.       &strip                     if $arg eq '-strip';   ## dump this program
  217.       last                       if $arg eq '-e';
  218.       $DELAY=$1,            next if $arg =~ m/-delay(\d+)/;
  219.  
  220.       $FIND_ONLY=1,         next if $arg =~/^-f(ind)?$/;## do "find" only
  221.  
  222.       $FIND_ONLY=1, $DOREP=1, $all=1,
  223.                             next if $arg =~/^-ff(ind)?$/;## fast -find
  224.       $LIST_ONLY=1,$opt{'-list'}=1,
  225.                     next if $arg =~/^-l(ist)?$/;## only list files
  226.  
  227.       if ($arg =~ m/^-(v+)$/) { ## verbosity
  228.     $VERBOSE =length($1);
  229.     foreach $len (1..$VERBOSE) { $opt{'-'.('v' x $len)}=1 }
  230.     next;
  231.       }
  232.       if ($arg =~ m/^-(n+)ice$/) { ## "nice" output
  233.         $NICE =length($1);
  234.     foreach $len (1..$NICE) { $opt{'-'.('n' x $len).'ice'}=1 }
  235.     next;
  236.       }
  237.  
  238.       if ($arg =~ m/^-(i?)(d?)skip$/) {
  239.       local($i) = $1 eq 'i';
  240.       local($d) = $2 eq 'd';
  241.       $! = 2, die qq/$0: expecting glob arg to -$arg\n/ unless @ARGV;
  242.       foreach (split(/\s+/, shift @ARGV)) {
  243.           if ($d) {
  244.           $idskip{$_}=1 if $i;
  245.            $dskip{$_}=1;
  246.           } else {
  247.           $iskip{$_}=1 if $i;
  248.            $skip{$_}=1;
  249.           }
  250.       }
  251.       next;
  252.       }
  253.  
  254.  
  255.       if ($arg =~ m/^-(i?)(d?)(regex|path|name)$/) {
  256.       local($i) = $1 eq 'i';
  257.       $! = 2, die qq/$0: expecting arg to -$arg\n/ unless @ARGV;
  258.       foreach (split(/\s+/, shift @ARGV)) {
  259.           $iname{join(',', $arg, $_)}=1 if $i;
  260.            $name{join(',', $arg, $_)}=1;
  261.       }
  262.       next;
  263.       }
  264.  
  265.       if ($arg =~ m/^-d?dir$/) {
  266.       $opt{'-dir'}=1;
  267.       $! = 2, die qq/$0: expecting filename arg to -$arg\n/ unless @ARGV;
  268.       $start = shift(@ARGV);
  269.       $start =~ s#^~(/+|$)#$ENV{'HOME'}$1# if defined $ENV{'HOME'};
  270.       $! = 2, die qq/$0: can't find ${arg}'s "$start"\n/ unless -e $start;
  271.       $! = 2, die qq/$0: ${arg}'s "$start" not a directory.\n/ unless -d _;
  272.       undef(@todo), $opt{'-ddir'}=1 if $arg eq '-ddir';
  273.       push(@todo, $start);
  274.       next;
  275.       }
  276.  
  277.       if ($arg =~ m/^-(new|old)er$/i) {
  278.       $! = 2, die "$0: expecting filename arg to -$arg\n" unless @ARGV;
  279.       local($file, $time) = shift(@ARGV);
  280.       $! = 2, die qq/$0: can't stat -${arg}'s "$file"./
  281.           unless $time = (stat($file))[$STAT_MTIME];
  282.       local($upper) = $arg =~ tr/A-Z//;
  283.       if ($arg =~ m/new/i) {
  284.          $time++ unless $upper;
  285.          $NEWER = $time if $NEWER < $time;
  286.       } else {
  287.          $time-- unless $upper;
  288.          $OLDER = $time if $OLDER == 0 || $OLDER > $time;
  289.       }
  290.       next;
  291.       }
  292.  
  293.       if ($arg =~ m/-mtime/) {
  294.       $! = 2, die "$0: expecting numerical arg to -$arg\n" unless @ARGV;
  295.       local($days) = shift(@ARGV);
  296.       $! = 2, die qq/$0: inappropriate arg ($days) to $arg\n/ if $days==0;
  297.       $days *= 3600 * 24;
  298.       if ($days < 0) {
  299.           local($time) = $^T + $days;
  300.           $NEWER = $time if $NEWER < $time;
  301.       } else {
  302.           local($time) = $^T - $days;
  303.             $OLDER = $time if $OLDER == 0 || $OLDER > $time;
  304.       }
  305.       next;
  306.       }
  307.  
  308.       ## special user options
  309.       if ($arg =~ m/^-x(.+)/) {
  310.       foreach (split(/[\s,]+/, $1)) {  $user_opt{$_} = $opt{$_}= 1;  }
  311.       next;
  312.       }
  313.  
  314.       $! = 2, die "$0: unknown arg [$arg]\n";
  315.   }
  316. }
  317.  
  318. ##
  319. ## Given a filename glob, return a regex.
  320. ## If the glob has no globbing chars (no * ? or [..]), then
  321. ## prepend an effective '*' to it.
  322. ##
  323. sub glob_to_regex
  324. {
  325.     local($glob) = @_;
  326.     local(@parts) = $glob =~ m/\\.|[*?]|\[]?[^]]*]|[^[\\*?]+/g;
  327.     local($trueglob)=0;
  328.     foreach (@parts) {
  329.     if ($_ eq '*' || $_ eq '?') {
  330.         $_ = ".$_";
  331.         $trueglob=1;  ## * and ? are a real glob
  332.     } elsif (substr($_, 0, 1) eq '[') {
  333.         $trueglob=1;  ## [..] is a real glob
  334.     } else {
  335.         s/^\\//;     ## remove any leading backslash;
  336.         s/\W/\\$&/g; ## now quote anything dangerous;
  337.     }
  338.     }
  339.     unshift(@parts, '.*') unless $trueglob;
  340.     join('', '^', @parts, '$');
  341. }
  342.  
  343. sub prepare_to_search
  344. {
  345.   local($rc_file) = @_;
  346.  
  347.   $HEADER_BYTES=0;          ## Might be set nonzero in &read_rc;
  348.   $last_message_length = 0; ## For &message and &clear_message.
  349.  
  350.   &read_rc($rc_file, $showrc) unless $norc;
  351.   exit(0) if $showrc;
  352.  
  353.   $NEXT_DIR_ENTRY = $DO_SORT ? 'shift @files' : 'readdir(DIR)';
  354.   $WHY = 1 if $VERBOSE > 3; ## Arg -vvvv or above implies  -why.
  355.   @todo = ('.') if @todo == 0; ## Where we'll start looking
  356.  
  357.   ## see if any user options were specified that weren't accounted for
  358.   foreach $opt (keys %user_opt) {
  359.       next if defined $seen_opt{$opt};
  360.       warn "warning: -x$opt never considered.\n";
  361.   }
  362.  
  363.   die "$0: multiple time constraints exclude all possible files.\n"
  364.       if ($NEWER && $OLDER) && ($NEWER > $OLDER);
  365.  
  366.   ##
  367.   ## Process any -skip/-iskip args that had been given
  368.   ##
  369.   local(@skip_test);
  370.   foreach $glob (keys %skip) {
  371.       $i = defined($iskip{$glob}) ? 'i': '';
  372.       push(@skip_test, '$name =~ m/'. &glob_to_regex($glob). "/$i");
  373.   }
  374.   if (@skip_test) {
  375.       $SKIP_TEST = join('||',@skip_test);
  376.       $DO_SKIP_TEST = 1;
  377.   } else {
  378.       $DO_SKIP_TEST = $SKIP_TEST = 0;
  379.   }
  380.  
  381.   ##
  382.   ## Process any -dskip/-idskip args that had been given
  383.   ##
  384.   local(@dskip_test);
  385.   foreach $glob (keys %dskip) {
  386.       $i = defined($idskip{$glob}) ? 'i': '';
  387.       push(@dskip_test, '$name =~ m/'. &glob_to_regex($glob). "/$i");
  388.   }
  389.   if (@dskip_test) {
  390.       $DSKIP_TEST = join('||',@dskip_test);
  391.       $DO_DSKIP_TEST = 1;
  392.   } else {
  393.       $DO_DSKIP_TEST = $DSKIP_TEST = 0;
  394.   }
  395.  
  396.  
  397.   ##
  398.   ## Process any -name, -path, -regex, etc. args that had been given.
  399.   ##
  400.   undef @name_test;
  401.   undef @dname_test;
  402.   foreach $key (keys %name) {
  403.       local($type, $pat) = split(/,/, $key, 2);
  404.       local($i) = defined($iname{$key}) ? 'i' : '';
  405.       if ($type =~ /regex/) {
  406.       $pat =~ s/!/\\!/g;
  407.       $test = "\$name =~ m!^$pat\$!$i";
  408.       } else {
  409.       local($var) = $type eq 'name' ? '$name' : '$file';
  410.       $test = "$var =~ m/". &glob_to_regex($pat). "/$i";
  411.       }
  412.       if ($type =~ m/^-i?d/) {
  413.       push(@dname_test, $test);
  414.       } else {
  415.       push(@name_test, $test);
  416.       }
  417.   }
  418.   if (@name_test) {
  419.       $GLOB_TESTS = join('||', @name_test);
  420.  
  421.       $DO_GLOB_TESTS = 1;
  422.   } else {
  423.       $GLOB_TESTS = $DO_GLOB_TESTS = 0;
  424.   }
  425.   if (@dname_test) {
  426.       $DGLOB_TESTS = join('||', @dname_test);
  427.       $DO_DGLOB_TESTS = 1;
  428.   } else {
  429.       $DGLOB_TESTS = $DO_DGLOB_TESTS = 0;
  430.   }
  431.  
  432.  
  433.   ##
  434.   ## Process any 'magic' things from the startup file.
  435.   ##
  436.   if (@magic_tests && $HEADER_BYTES) {
  437.       ## the $magic' one is for when &dodir is not inlined
  438.       $tests = join('||',@magic_tests);
  439.       $MAGIC_TESTS = " { package magic; \$val = ($tests) }";
  440.       $DO_MAGIC_TESTS = 1;
  441.   } else {
  442.       $MAGIC_TESTS = 1;
  443.       $DO_MAGIC_TESTS = 0;
  444.   }
  445.  
  446.   ##
  447.   ## Prepare regular expressions.
  448.   ##
  449.   {
  450.       local(@regex_tests);
  451.  
  452.       if ($LIST_ONLY) {
  453.      $mflag = '';
  454.      ## need to have $* set, but perl5 just won''t shut up about it.
  455.      if ($] >= 5) {
  456.           $mflag = 'm';
  457.      } else {
  458.           eval ' $* = 1 ';
  459.      }
  460.       }
  461.  
  462.       ##
  463.       ## Until I figure out a better way to deal with it,
  464.       ## We have to worry about a regex like [^xyz] when doing $LIST_ONLY.
  465.       ## Such a regex *will* match \n, and if I'm pulling in multiple
  466.       ## lines, it can allow lines to match that would otherwise not match.
  467.       ##
  468.       ## Therefore, if there is a '[^' in a regex, we can NOT take a chance
  469.       ## an use the fast listonly.
  470.       ##
  471.       $CAN_USE_FAST_LISTONLY = $LIST_ONLY;
  472.  
  473.       local(@extra);
  474.       local($underline_glue) = ($] >= 5) ? '(:?_\cH)?' : '(_\cH)?';
  475.       while (@ARGV) {
  476.           $regex = shift(@ARGV);
  477.       ##
  478.       ## If watching for underlined things too, add another regex.
  479.       ##
  480.       if ($underlineOK) {
  481.          if ($regex =~ m/[?*+{}()\\.|^\$[]/) {
  482.         warn "$0: warning, can't underline-safe ``$regex''.\n";
  483.          } else {
  484.         $regex = join($underline_glue, split(//, $regex));
  485.          }
  486.       }
  487.  
  488.       ## If nothing special in the regex, just use index...
  489.       ## is quite a bit faster.
  490.       if (($iflag eq '') && ($words == 0) &&
  491.             $regex !~ m/[?*+{}()\\.|^\$[]/)
  492.       {
  493.           push(@regex_tests, "(index(\$_, q+$regex+)>=0)");
  494.  
  495.       } else {
  496.           $regex =~ s#[\$\@\/]\w#\\$&#;
  497.           if ($words) {
  498.           if ($regex =~ m/\|/) {
  499.               ## could be dangerous -- see if we can wrap in parens.
  500.               if ($regex =~ m/\\\d/) {
  501.               warn "warning: -w and a | in a regex is dangerous.\n"
  502.               } else {
  503.               $regex = join($regex, '(', ')');
  504.               }
  505.           }
  506.           $regex = join($regex, '\b', '\b');
  507.           }
  508.           $CAN_USE_FAST_LISTONLY = 0 if substr($regex, "[^") >= 0;
  509.           push(@regex_tests, "m/$regex/$iflag$mflag");
  510.       }
  511.  
  512.       ## If we're done, but still have @extra to do, get set for that.
  513.       if (@ARGV == 0 && @extra) {
  514.           @ARGV = @extra;   ## now deal with the extra stuff.
  515.           $underlineOK = 0; ## but no more of this.
  516.           undef @extra;     ## or this.
  517.       }
  518.       }
  519.       if (@regex_tests) {
  520.       $REGEX_TEST = join('||', @regex_tests);
  521.       ## print STDERR $REGEX_TEST, "\n"; exit;
  522.       } else {
  523.       ## must be doing -find -- just give something syntactically correct.
  524.       $REGEX_TEST = 1;
  525.       }
  526.   }
  527.  
  528.   ##
  529.   ## Make sure we can read the first item(s).
  530.   ##
  531.   foreach $start (@todo) {
  532.       $! = 2, die qq/$0: can't stat "$start"\n/
  533.       unless ($dev,$inode) = (stat($start))[$STAT_DEV,$STAT_INODE];
  534.  
  535.       if (defined $dir_done{"$dev,$inode"}) {
  536.       ## ignore the repeat.
  537.       warn(qq/ignoring "$start" (same as "$dir_done{"$dev,$inode"}").\n/)
  538.         if $VERBOSE;
  539.       next;
  540.       }
  541.  
  542.       ## if -xdev was given, remember the device.
  543.       $xdev{$dev} = 1 if $XDEV;
  544.  
  545.       ## Note that we won't want to do it again
  546.       $dir_done{"$dev,$inode"} = $start;
  547.   }
  548. }
  549.  
  550.  
  551. ##
  552. ## See the comment above the __END__ above the 'sub dodir' below.
  553. ##
  554. sub import_program
  555. {
  556.     sub bad {
  557.     print STDERR "$0: internal error (@_)\n";
  558.     exit 2;
  559.     }
  560.  
  561.     ## Read from data, up to next __END__. This will be &dodir.
  562.     local($/) = "\n__END__";
  563.     $prog = <DATA>;
  564.     close(DATA);
  565.  
  566.     $prog =~ s/\beval\b//g;       ## remove any 'eval'
  567.  
  568.     ## Inline uppercase $-variables by their current values.
  569.     if ($] >= 5) {
  570.     $prog =~ s/\$([A-Z][A-Z0-9_]{2,}\b)/
  571.             &bad($1) if !defined ${$main::{$1}}; ${$main::{$1}};/eg;
  572.     } else {
  573.     $prog =~ s/\$([A-Z][A-Z0-9_]{2,}\b)/local(*VAR) = $_main{$1};
  574.             &bad($1) if !defined $VAR; $VAR;/eg;
  575.     }
  576.  
  577.     eval $prog;  ## now do it. This will define &dodir;
  578.     $!=2, die "$0 internal error: $@\n" if $@;
  579. }
  580.  
  581. ###########################################################################
  582.  
  583. ##
  584. ## Read the .search file:
  585. ##    Blank lines and lines that are only #-comments ignored.
  586. ##    Newlines may be escaped to create long lines
  587. ##    Other lines are directives.
  588. ##
  589. ##    A directive may begin with an optional tag in the form <...>
  590. ##    Things inside the <...> are evaluated as with:
  591. ##       <(this || that) && must>
  592. ##    will be true if
  593. ##       -xmust -xthis   or   -xmust -xthat
  594. ##    were specified on the command line (order doesn't matter, though)
  595. ##    A directive is not done if there is a tag and it's false.
  596. ##    Any characters but whitespace and &|()>,! may appear after an -x
  597. ##    (although "-xdev" is special).  -xmust,this is the same as -xmust -xthis.
  598. ##    Something like -x~ would make <~> true, and <!~> false.
  599. ##
  600. ##    Directives are in the form:
  601. ##      option: STRING
  602. ##    magic : NUMBYTES : EXPR
  603. ##
  604. ##    With option:
  605. ##      The STRING is parsed like a Bourne shell command line, and the
  606. ##      options are used as if given on the command line.
  607. ##      No comments are allowed on 'option' lines.
  608. ##    Examples:
  609. ##        # skip objects and libraries
  610. ##        option: -skip '.o .a'
  611. ##        # skip emacs *~ and *# files, unless -x~ given:
  612. ##        <!~> option: -skip '~ #'
  613. ##
  614. ##    With magic:
  615. ##    EXPR can be pretty much any perl (comments allowed!).
  616. ##      If it evaluates to true for any particular file, it is skipped.
  617. ##      The only info you'll have about a file is the variable $H, which
  618. ##      will have at least the first NUMBYTES of the file (less if the file
  619. ##      is shorter than that, of course, and maybe more). You'll also have
  620. ##      any variables you set in previous 'magic' lines.
  621. ##    Examples:
  622. ##        magic: 6 : ($x6 = substr($H, 0, 6)) eq 'GIF87a'
  623. ##        magic: 6 :  $x6                     eq 'GIF89a'
  624. ##
  625. ##          magic: 6 : (($x6 = substr($H, 0, 6)) eq 'GIF87a' ## old gif \
  626. ##                                 || $x6  eq 'GIF89a' ## new gif
  627. ##    (the above two sets are the same)
  628. ##        ## Check the first 32 bytes for "binarish" looking bytes.
  629. ##        ## Don't blindly dump on any high-bit set, as non-ASCII text
  630. ##        ## often has them set. \x80 and \xff seem to be special, though.
  631. ##        ## Require two in a row to not get things like perl's $^T.
  632. ##        ## This is known to get *.Z, *.gz, pkzip, *.elc and about any
  633. ##        ## executable you'll find.
  634. ##        magic: 32 : $H =~ m/[\x00-\x06\x10-\x1a\x1c-\x1f\x80\xff]{2}/
  635. ##
  636. sub read_rc
  637. {
  638.     local($file, $show) = @_;
  639.     local($line_num, $ln, $tag) = 0;
  640.     local($use_default, @default) = 0;
  641.  
  642.     { package magic; $^W= 0; } ## turn off warnings for when we run EXPR's
  643.  
  644.     unless (open(RC, "$file")) {
  645.     $use_default=1;
  646.     $file = "<internal default startup file>";
  647.     ## no RC file -- use this default.
  648.     @default = split(/\n/,<<'--------INLINE_LITERAL_TEXT');
  649.             magic: 32 : $H =~ m/[\x00-\x06\x10-\x1a\x1c-\x1f\x80\xff]{2}/
  650.         option: -skip '.a .elc .gz .o .pbm .xbm .dvi'
  651.         option: -iskip '.com .exe .lib .pdb .tarz .zip .z .lzh .jpg .jpeg .gif .uu'
  652.         <!~> option: -skip '~ #'
  653. --------INLINE_LITERAL_TEXT
  654.     }
  655.  
  656.     ##
  657.     ## Make an eval error pretty.
  658.     ##
  659.     sub clean_eval_error {
  660.     local($_) = @_;
  661.     s/ in file \(eval\) at line \d+,//g; ## perl4-style error
  662.     s/ at \(eval \d+\) line \d+,//g;     ## perl5-style error
  663.     $_ = $` if m/\n/;                    ## remove all but first line
  664.     "$_\n";
  665.     }
  666.  
  667.     print "reading RC file: $file\n" if $show;
  668.  
  669.     while (defined($_ = ($use_default ? shift(@default) : <RC>))) {
  670.     $ln = ++$line_num;                 ## note starting line num.
  671.         $_ .= <RC>, $line_num++ while s/\\\n?$/\n/;  ## allow continuations
  672.     next if /^\s*(#.*)?$/;          ## skip blank or comment-only lines.
  673.         $do = '';
  674.     
  675.     ## look for an initial <...> tag.
  676.     if (s/^\s*<([^>]*)>//) {
  677.         ## This simple s// will make the tag ready to eval.
  678.         ($tag = $msg = $1) =~
  679.         s/[^\s&|(!)]+/
  680.             $seen_opt{$&}=1;         ## note seen option
  681.             "defined(\$opt{q>$&>})"  ## (q>> is safe quoting here)
  682.         /eg;
  683.         
  684.         ## see if the tag is true or not, abort this line if not.
  685.         $dothis = (eval $tag);
  686.         $!=2, die "$file $ln <$msg>: $_".&clean_eval_error($@) if $@;
  687.  
  688.         if ($show) {
  689.             $msg =~ s/[^\s&|(!)]+/-x$&/;
  690.             $msg =~ s/\s*!\s*/ no /g;
  691.             $msg =~ s/\s*&&\s*/ and /g;
  692.             $msg =~ s/\s*\|\|\s*/ or /g;
  693.         $msg =~ s/^\s+//; $msg =~ s/\s+$//;
  694.         $do = $dothis ? "(doing because $msg)" :
  695.                 "(do if $msg)";
  696.         } elsif (!$dothis) {
  697.             next;
  698.         }
  699.     }
  700.  
  701.     if (m/^\s*option\s*:\s*/) {
  702.         next if $all && !$show; ## -all turns off these checks;
  703.         local($_) = $';
  704.             s/\n$//;
  705.         local($orig) = $_;
  706.         print " $do option: $_\n" if $show;
  707.         local($0) = "$0 ($file)"; ## for any error message.
  708.         local(@ARGV);
  709.         local($this);
  710.         ##
  711.         ## Parse $_ as a Bourne shell line -- fill @ARGV
  712.         ##
  713.         while (length) {
  714.         if (s/^\s+//) {
  715.             push(@ARGV, $this) if defined $this;
  716.             undef $this;
  717.             next;
  718.         }
  719.         $this = '' if !defined $this;
  720.         $this .= $1 while s/^'([^']*)'// ||
  721.                   s/^"([^"]*)"// ||
  722.                   s/^([^'"\s\\]+)//||
  723.                   s/^(\\[\D\d])//;
  724.         die "$file $ln: error parsing $orig at $_\n" if m/^\S/;
  725.         }
  726.         push(@ARGV, $this) if defined $this;
  727.         &check_args;
  728.         die qq/$file $ln: unused arg "@ARGV".\n/ if @ARGV;
  729.         next;
  730.     }
  731.  
  732.     if (m/^\s*magic\s*:\s*(\d+)\s*:\s*/) {
  733.         next if $all && !$show; ## -all turns off these checks;
  734.         local($bytes, $check) = ($1, $');
  735.  
  736.         if ($show) {
  737.         $check =~ s/\n?$/\n/;
  738.         print " $do contents: $check";
  739.         }
  740.         ## Check to make sure the thing at least compiles.
  741.         eval  "package magic; (\$H = '1'x \$main'bytes) && (\n$check\n)\n";
  742.         $! = 2, die "$file $ln: ".&clean_eval_error($@) if $@;
  743.  
  744.         $HEADER_BYTES = $bytes if $bytes > $HEADER_BYTES;
  745.         push(@magic_tests, "(\n$check\n)");
  746.         next;
  747.     }
  748.     $! = 2, die "$file $ln: unknown command\n";
  749.     }
  750.     close(RC);
  751. }
  752.  
  753. sub message
  754. {
  755.     if (!$STDERR_IS_TTY) {
  756.     print STDERR $_[0], "\n";
  757.     } else {
  758.     local($text) = @_;
  759.     $thislength = length($text);
  760.     if ($thislength >= $last_message_length) {
  761.         print STDERR $text, "\r";
  762.     } else {
  763.         print STDERR $text, ' 'x ($last_message_length-$thislength),"\r";
  764.     }    
  765.     $last_message_length = $thislength;
  766.     }
  767. }
  768.  
  769. sub clear_message
  770. {
  771.     print STDERR ' ' x $last_message_length, "\r" if $last_message_length;
  772.     $vv_print = $vv_size = $last_message_length = 0;
  773. }
  774.  
  775. ##
  776. ## Output a copy of this program with comments, extra whitespace, and
  777. ## the trailing man page removed. On an ultra slow machine, such a copy
  778. ## might load faster (but I can't tell any difference on my machine).
  779. ##
  780. sub strip {
  781.     seek(DATA, 0, 0) || die "$0: can't reset internal pointer.\n";
  782.     while(<DATA>) {
  783.       print, next if /INLINE_LITERAL_TEXT/.../INLINE_LITERAL_TEXT/;
  784.       ## must mention INLINE_LITERAL_TEXT on this line!
  785.       s/\#\#.*|^\s+|\s+$//; ## remove cruft
  786.       last if $_ eq '.00;';
  787.       next if ($_ eq '') || ($_ eq "'di'") || ($_ eq "'ig00'");
  788.       s/\$stripped=0;/\$stripped=1;/;
  789.       s/\s\s+/ /;  ## squish multiple whitespaces down to one.
  790.       print $_, "\n";
  791.     }
  792.     exit(0);
  793. }
  794.  
  795. ##
  796. ## Just to shut up -w. Never executed.
  797. ##
  798. sub dummy {
  799.  
  800.     1 || &dummy || &dir_done || &bad || &message || $NEXT_DIR_ENTRY ||
  801.     $DELAY || $VV_SIZE || $VV_PRINT_COUNT || $STDERR_SCREWS_STDOUT ||
  802.     @files || @files || $magic'H || $magic'H || $xdev{''} || &clear_message;
  803.  
  804. }
  805.  
  806. ##
  807. ## If the following __END__ is in place, what follows will be
  808. ## inlined when the program first starts up. Any $ variable name
  809. ## all in upper case, specifically, any string matching
  810. ##    \$([A-Z][A-Z0-9_]{2,}\b
  811. ## will have the true value for that variable inlined. Also, any 'eval' is
  812. ## removed
  813. ##
  814. ## The idea is that when the whole thing is then eval'ed to define &dodir,
  815. ## the perl optimizer will make all the decisions that are based upon
  816. ## command-line options (such as $VERBOSE), since they'll be inlined as
  817. ## constants
  818. ##
  819. ## Also, and here's the big win, the tests for matching the regex, and a
  820. ## few others, are all inlined. Should be blinding speed here.
  821. ##
  822. ## See the read from <DATA> above for where all this takes place.
  823. ## But all-in-all, you *want* the __END__ here. Comment it out only for
  824. ## debugging....
  825. ##
  826.  
  827. __END__
  828.  
  829. ##
  830. ## Given a directory, check all "appropriate" files in it.
  831. ## Shove any subdirectories into the global @todo, so they'll be done
  832. ## later.
  833. ##
  834. ## Be careful about adding any upper-case variables, as they are subject
  835. ## to being inlined. See comments above the __END__ above.
  836. ##
  837. sub dodir
  838. {
  839.   local($dir) = @_;
  840.   $dir =~ s,/+$,,; ## remove any trailing slash.
  841.   unless (opendir(DIR, "$dir/.")) {
  842.       &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;
  843.       warn qq($0: can't opendir "$dir/".\n);
  844.       return;
  845.   }
  846.  
  847.   if ($VERBOSE) {
  848.       &message($dir);
  849.       $vv_print = $vv_size = 0;
  850.   }
  851.  
  852.   @files = sort readdir(DIR) if $DO_SORT;
  853.  
  854.   while (defined($name = eval $NEXT_DIR_ENTRY))
  855.   {
  856.     next if $name eq '.' || $name eq '..'; ## never follow these.
  857.  
  858.     ## create full relative pathname.
  859.     $file = $dir eq '.' ? $name : "$dir/$name";
  860.  
  861.     ## if link and skipping them, do so.
  862.     if ($NOLINKS && -l $file) {
  863.     warn qq/skip (symlink): $file\n/ if $WHY;
  864.     next;
  865.     }
  866.  
  867.     ## skip things unless files or directories
  868.     unless (-f $file || -d _) {
  869.     if ($WHY) {
  870.         $why = (-S _ && "socket")       ||
  871.            (-p _ && "pipe")         ||
  872.            (-b _ && "block special")||
  873.            (-c _ && "char special") || "somekinda special";
  874.         warn qq/skip ($why): $file\n/;
  875.     }
  876.     next;
  877.     }
  878.  
  879.     ## skip things we can't read
  880.     unless (-r _) {
  881.     if ($WHY) {
  882.         $why = (-l $file) ? "follow" : "read";
  883.         warn qq/skip (can't $why): $file\n/;
  884.     }
  885.     next;
  886.     }
  887.  
  888.     ## skip things that are empty
  889.     unless (-s _ || -d _) {
  890.     warn qq/skip (empty): $file\n/ if $WHY;
  891.     next;
  892.     }
  893.  
  894.     ## Note file device & inode. If -xdev, skip if appropriate.
  895.     ($dev, $inode) = (stat(_))[$STAT_DEV, $STAT_INODE];
  896.     if ($XDEV && defined $xdev{$dev}) {
  897.     warn qq/skip (other device): $file\n/ if $WHY;
  898.     next;
  899.     }
  900.     $id = "$dev,$inode";
  901.  
  902.     ## special work for a directory
  903.     if (-d _) {
  904.     ## Do checks for directory file endings.
  905.     if ($DO_DSKIP_TEST && (eval $DSKIP_TEST)) {
  906.         warn qq/skip (-dskip): $file\n/ if $WHY;
  907.         next;
  908.     }
  909.     ## do checks for -name/-regex/-path tests
  910.     if ($DO_DGLOB_TESTS && !(eval $DGLOB_TESTS)) {
  911.         warn qq/skip (dirname): $file\n/ if $WHY;
  912.         next;
  913.     }
  914.  
  915.     ## _never_ redo a directory
  916.     if (defined $dir_done{$id} and $^O ne 'MSWin32') {
  917.         warn qq/skip (did as "$dir_done{$id}"): $file\n/ if $WHY;
  918.         next;
  919.     }
  920.     $dir_done{$id} = $file;     ## mark it done.
  921.     unshift(@todo, $file);        ## add to the list to do.
  922.     next;
  923.     }
  924.     if ($WHY == 0  && $VERBOSE > 1) {
  925.       if ($VERBOSE>2||$vv_print++>$VV_PRINT_COUNT||($vv_size+=-s _)>$VV_SIZE){
  926.       &message($file);
  927.       $vv_print = $vv_size = 0;
  928.       }
  929.     }
  930.  
  931.     ## do time-related tests
  932.     if ($NEWER || $OLDER) {
  933.     $_ = (stat(_))[$STAT_MTIME];
  934.     if ($NEWER && $_ < $NEWER) {
  935.         warn qq/skip (too old): $file\n/ if $WHY;
  936.         next;
  937.     }
  938.     if ($OLDER && $_ > $OLDER) {
  939.         warn qq/skip (too new): $file\n/ if $WHY;
  940.         next;
  941.     }
  942.     }
  943.  
  944.     ## do checks for file endings
  945.     if ($DO_SKIP_TEST && (eval $SKIP_TEST)) {
  946.     warn qq/skip (-skip): $file\n/ if $WHY;
  947.     next;
  948.     }
  949.  
  950.     ## do checks for -name/-regex/-path tests
  951.     if ($DO_GLOB_TESTS && !(eval $GLOB_TESTS)) {
  952.     warn qq/skip (filename): $file\n/ if $WHY;
  953.     next;
  954.     }
  955.  
  956.  
  957.     ## If we're not repeating files,
  958.     ##    skip this one if we've done it, or note we're doing it.
  959.     unless ($DOREP) {
  960.     if (defined $file_done{$id}) {
  961.         warn qq/skip (did as "$file_done{$id}"): $file\n/ if $WHY;
  962.         next;
  963.     }
  964.     $file_done{$id} = $file;
  965.     }
  966.  
  967.     if ($DO_MAGIC_TESTS) {
  968.     if (!open(FILE_IN, $file)) {
  969.         &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;
  970.         warn qq/$0: can't open: $file\n/;
  971.         next;
  972.     }
  973.     unless (read(FILE_IN, $magic'H, $HEADER_BYTES)) {
  974.         &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;
  975.         warn qq/$0: can't read from "$file"\n"/;
  976.         close(FILE_IN);
  977.         next;
  978.     }
  979.  
  980.     eval $MAGIC_TESTS;
  981.     if ($magic'val) {
  982.         close(FILE_IN);
  983.         warn qq/skip (magic): $file\n/ if $WHY;
  984.         next;
  985.     }
  986.     seek(FILE_IN, 0, 0);  ## reset for later <FILE_IN>
  987.     }
  988.  
  989.     if ($WHY != 0  && $VERBOSE > 1) {
  990.       if ($VERBOSE>2||$vv_print++>$VV_PRINT_COUNT||($vv_size+=-s _)>$VV_SIZE){
  991.       &message($file);
  992.       $vv_print = $vv_size = 0;
  993.       }
  994.     }
  995.  
  996.     if ($DELAY) {
  997.     sleep($DELAY);
  998.     }
  999.  
  1000.     if ($FIND_ONLY) {
  1001.     &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;
  1002.     print $file, "\n";
  1003.     $retval=0; ## we've found something
  1004.     close(FILE_IN) if $DO_MAGIC_TESTS;
  1005.     next;
  1006.     } else {
  1007.     ## if we weren't doing magic tests, file won't be open yet...
  1008.     if (!$DO_MAGIC_TESTS && !open(FILE_IN, $file)) {
  1009.         &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;
  1010.         warn qq/$0: can't open: $file\n/;
  1011.         next;
  1012.     }
  1013.     if ($LIST_ONLY && $CAN_USE_FAST_LISTONLY) {
  1014.         ##
  1015.         ## This is rather complex, but buys us a LOT when we're just
  1016.         ## listing files and not the individual internal lines.
  1017.         ##
  1018.         local($size) = 4096;  ## block-size in which to do reads
  1019.         local($nl);           ## will point to $_'s ending newline.
  1020.         local($read);      ## will be how many bytes read.
  1021.         local($_) = '';       ## Starts out empty
  1022.         local($hold);      ## (see below)
  1023.  
  1024.         while (($read = read(FILE_IN,$_,$size,length($_)))||length($_))
  1025.         {
  1026.         undef @parts;
  1027.         ## if read a full block, but no newline, need to read more.
  1028.         while ($read == $size && ($nl = rindex($_, "\n")) < 0) {
  1029.             push(@parts, $_);                    ## save that part
  1030.             $read = read(FILE_IN, $_, $size); ## keep trying
  1031.         }
  1032.  
  1033.         ##
  1034.         ## If we had to save parts, must now combine them together.
  1035.         ## adjusting $nl to reflect the now-larger $_. This should
  1036.         ## be a lot more efficient than using any kind of .= in the
  1037.         ## loop above.
  1038.         ##
  1039.         if (@parts) {
  1040.             local($lastlen) = length($_); #only need if $nl >= 0
  1041.             $_ = join('', @parts, $_);
  1042.             $nl = length($_) - ($lastlen - $nl) if $nl >= 0;
  1043.         }
  1044.  
  1045.         ##
  1046.         ## If we're at the end of the file, then we can use $_ as
  1047.         ## is.  Otherwise, we need to remove the final partial-line
  1048.         ## and save it so that it'll be at the beginning of the
  1049.         ## next read (where the rest of the line will be layed in
  1050.         ## right after it).  $hold will be what we should save
  1051.         ## until next time.
  1052.         ##
  1053.         if ($read != $size || $nl < 0) {
  1054.             $hold = '';
  1055.         } else {
  1056.             $hold = substr($_, $nl + 1);
  1057.             substr($_, $nl + 1) = '';
  1058.         }
  1059.  
  1060.         ##
  1061.         ## Now have a bunch of full lines in $_. Use it.
  1062.         ##
  1063.         if (eval $REGEX_TEST) {
  1064.             &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;
  1065.             print $file, "\n";
  1066.             $retval=0; ## we've found something
  1067.  
  1068.             last;
  1069.         }
  1070.  
  1071.         ## Prepare for next read....
  1072.         $_ = $hold;
  1073.         }
  1074.  
  1075.     } else {  ## else not using faster block scanning.....
  1076.  
  1077.             $lines_printed = 0 if $NICE;
  1078.         while (<FILE_IN>) {
  1079.         study;
  1080.         next unless (eval $REGEX_TEST);
  1081.  
  1082.         ##
  1083.         ## We found a matching line.
  1084.         ##
  1085.         $retval=0;
  1086.         &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;
  1087.         if ($LIST_ONLY) {
  1088.             print $file, "\n";
  1089.             last;
  1090.         } else {
  1091.             ## prepare to print line.
  1092.             if ($NICE && $lines_printed++ == 0) {
  1093.             print '-' x 70, "\n" if $NICE > 1;
  1094.             print $file, ":\n";
  1095.             }
  1096.  
  1097.             ##
  1098.             ## Print all the prelim stuff. This looks less efficient
  1099.             ## than it needs to be, but that's so that when the eval
  1100.             ## is compiled (and the tests are optimized away), the
  1101.             ## result will be less actual PRINTs than the more natural
  1102.             ## way of doing these tests....
  1103.             ##
  1104.             if ($NICE) {
  1105.             if ($REPORT_LINENUM) {
  1106.                 print " line $.:  ";
  1107.             } else {
  1108.                 print "  ";
  1109.             }
  1110.             } elsif ($REPORT_LINENUM && $PREPEND_FILENAME) {
  1111.             print "$file,:$.: ";
  1112.             } elsif ($PREPEND_FILENAME) {
  1113.             print "$file: ";
  1114.             } elsif ($REPORT_LINENUM) {
  1115.             print "$.: ";
  1116.             }
  1117.             print $_;
  1118.             print "\n" unless m/\n$/;
  1119.         }
  1120.         }
  1121.         print "\n" if ($NICE > 1) && $lines_printed;
  1122.     }
  1123.     close(FILE_IN);
  1124.     }
  1125.   }
  1126.   closedir(DIR);
  1127. }
  1128.  
  1129. __END__
  1130. .00;            ## finish .ig
  1131.  
  1132. 'di            \" finish diversion--previous line must be blank
  1133. .nr nl 0-1        \" fake up transition to first page again
  1134. .nr % 0            \" start at page 1
  1135. .\"__________________NORMAL_MAN_PAGE_BELOW_________________
  1136. .ll+10n
  1137. .TH search 1 "Dec 17, 1994"
  1138. .SH SEARCH
  1139. search \- search files (a'la grep) in a whole directory tree.
  1140. .SH SYNOPSIS
  1141. search [ grep-like and find-like options] [regex ....]
  1142. .SH DESCRIPTION
  1143. .I Search
  1144. is more or less a combo of 'find' and 'grep' (although the regular
  1145. expression flavor is that of the perl being used, which is closer to
  1146. egrep's than grep's).
  1147.  
  1148. .I Search
  1149. does generally the same kind of thing that
  1150. .nf
  1151.    find <blah blah> | xargs egrep <blah blah>
  1152. .fi
  1153. does, but is
  1154. .I much
  1155. more powerful and efficient (and intuitive, I think).
  1156.  
  1157. This manual describes
  1158. .I search
  1159. as of version "941227.4". You can always find the latest version at
  1160. .nf
  1161.    http://www.wg.omron.co.jp/~jfriedl/perl/index.html
  1162. .fi
  1163.  
  1164. .SH "QUICK EXAMPLE"
  1165. Basic use is simple:
  1166. .nf
  1167.     % search jeff
  1168. .fi
  1169. will search files in the current directory, and all sub directories, for
  1170. files that have "jeff" in them. The lines will be listed with the
  1171. containing file's name prepended.
  1172. .PP
  1173. If you list more than one regex, such as with
  1174. .nf
  1175.     % search jeff Larry Randal+ 'Stoc?k' 'C.*son'
  1176. .fi
  1177. then a line containing any of the regexes will be listed.
  1178. This makes it effectively the same as
  1179. .nf
  1180.     % search 'jeff|Larry|Randal+|Stoc?k|C.*son'
  1181. .fi
  1182. However, listing them separately is much more efficient (and is easier
  1183. to type).
  1184. .PP
  1185. Note that in the case of these examples, the
  1186. .B \-w
  1187. (list whole-words only) option would be useful.
  1188. .PP
  1189. Normally, various kinds of files are automatically removed from consideration.
  1190. If it has has a certain ending (such as ".tar", ".Z", ".o", .etc), or if
  1191. the beginning of the file looks like a binary, it'll be excluded.
  1192. You can control exactly how this works -- see below. One quick way to
  1193. override this is to use the
  1194. .B \-all
  1195. option, which means to consider all the files that would normally be
  1196. automatically excluded.
  1197. Or, if you're curious, you can use
  1198. .B \-why
  1199. to have notes about what files are skipped (and why) printed to stderr.
  1200.  
  1201. .SH "BASIC OVERVIEW"
  1202. Normally, the search starts in the current directory, considering files in
  1203. all subdirectories.
  1204.  
  1205. You can use the
  1206. .I ~/.search
  1207. file to control ways to automatically exclude files.
  1208. If you don't have this file, a default one will kick in, which automatically
  1209. add
  1210. .nf
  1211.     -skip .o .Z .gif
  1212. .fi
  1213. (among others) to exclude those kinds of files (which you probably want to
  1214. skip when searching for text, as is normal).
  1215. Files that look to be be binary will also be excluded.
  1216.  
  1217. Files ending with "#" and "~" will also be excluded unless the
  1218. .B -x~
  1219. option is given. 
  1220.  
  1221. You can use
  1222. .B -showrc
  1223. to show what kinds of files will normally be skipped.
  1224. See the section on the startup file
  1225. for more info.
  1226.  
  1227. You can use the
  1228. .B -all
  1229. option to indicate you want to consider all files that would otherwise be
  1230. skipped by the startup file.
  1231.  
  1232. Based upon various other flags (see "WHICH FILES TO CONSIDER" below),
  1233. more files might be removed from consideration. For example
  1234. .nf
  1235.     -mtime 3
  1236. .fi
  1237. will exclude files that aren't at least three days old (change the 3 to -3
  1238. to exclude files that are more than three days old), while
  1239. .nf
  1240.     -skip .*
  1241. .fi
  1242. would exclude any file beginning with a dot (of course, '.' and '..'  are
  1243. special and always excluded).
  1244.  
  1245. If you'd like to see what files are being excluded, and why, you can get the
  1246. list via the
  1247. .B \-why
  1248. option.
  1249.  
  1250. If a file makes it past all the checks, it is then "considered".
  1251. This usually means it is greped for the regular expressions you gave
  1252. on the command line.
  1253.  
  1254. If any of the regexes match a line, the line is printed.
  1255. However, if
  1256. .B -list
  1257. is given, just the filename is printed. Or, if
  1258. .B -nice
  1259. is given, a somewhat more (human-)readable output is generated.
  1260.  
  1261. If you're searching a huge tree and want to keep informed about how
  1262. the search is progressing,
  1263. .B -v
  1264. will print (to stderr) the current directory being searched.
  1265. Using
  1266. .B -vv
  1267. will also print the current file "every so often", which could be useful
  1268. if a directory is huge. Using
  1269. .B -vvv
  1270. will print the update with every file.
  1271.  
  1272. Below is the full listing of options.
  1273.  
  1274. .SH "OPTIONS TELLING *WHERE* TO SEARCH"
  1275. .TP
  1276. .BI -dir " DIR"
  1277. Start searching at the named directory instead of the current directory.
  1278. If multiple
  1279. .B -dir
  1280. arguments are given, multiple trees will be searched.
  1281. .TP
  1282. .BI -ddir " DIR"
  1283. Like
  1284. .B -dir
  1285. except it flushes any previous
  1286. .B -dir
  1287. directories (i.e. "-dir A -dir B -dir C" will search A, B, and C, while
  1288. "-dir A -ddir B -dir C" will search only B and C. This might be of use
  1289. in the startup file (see that section below).
  1290. .TP
  1291. .B -xdev
  1292. Stay on the same filesystem as the starting directory/directories.
  1293. .TP
  1294. .B -sort
  1295. Sort the items in a directory before processing them.
  1296. Normally they are processed in whatever order they happen to be read from
  1297. the directory.
  1298. .TP
  1299. .B -nolinks
  1300. Don't follow symbolic links. Normally they're followed.
  1301.  
  1302. .SH "OPTIONS CONTROLLING WHICH FILES TO CONSIDER AND EXCLUDE"
  1303. .TP
  1304. .BI -mtime " NUM"
  1305. Only consider files that were last changed more than
  1306. .I NUM
  1307. days ago
  1308. (less than
  1309. .I NUM
  1310. days if
  1311. .I NUM
  1312. has '-' prepended, i.e. "-mtime -2.5" means to consider files that
  1313. have been changed in the last two and a half days).
  1314. .TP
  1315. .B -older FILE
  1316. Only consider files that have not changed since
  1317. .I FILE
  1318. was last changed.
  1319. If there is any upper case in the "-older", "or equal" is added to the sense
  1320. of the test.  Therefore, "search -older ./file regex" will never consider
  1321. "./file", while "search -Older ./file regex" will.
  1322.  
  1323. If a file is a symbolic link, the time used is that of the file and not the
  1324. link.
  1325. .TP
  1326. .BI -newer " FILE"
  1327. Opposite of
  1328. .BR -older .
  1329. .TP
  1330. .BI -name " GLOB"
  1331. Only consider files that match the shell filename pattern
  1332. .IR GLOB .
  1333. The check is only done on a file's name (use
  1334. .B -path
  1335. to check the whole path, and use
  1336. .B -dname
  1337. to check directory names).
  1338.  
  1339. Multiple specifications can be given by separating them with spaces, a'la
  1340. .nf
  1341.     -name '*.c *.h'
  1342. .fi
  1343. to consider C source and header files.
  1344. If
  1345. .I GLOB
  1346. doesn't contain any special pattern characters, a '*' is prepended.
  1347. This last example could have been given as
  1348. .nf
  1349.    -name '.c .h'
  1350. .fi
  1351. It could also be given as
  1352. .nf
  1353.     -name .c -name .h
  1354. .fi
  1355. or
  1356. .nf
  1357.     -name '*.c' -name '*.h'
  1358. .fi
  1359. or
  1360. .nf
  1361.     -name '*.[ch]'
  1362. .fi
  1363. (among others)
  1364. but in this last case, you have to be sure to supply the leading '*'.
  1365. .TP
  1366. .BI -path " GLOB"
  1367. Like
  1368. .B -name
  1369. except the entire path is checked against the pattern.
  1370. .TP
  1371. .B -regex " REGEX"
  1372. Considers files whose names (not paths) match the given perl regex
  1373. exactly.
  1374. .TP
  1375. .BI -iname " GLOB"
  1376. Case-insensitive version of
  1377. .BR -name .
  1378. .TP
  1379. .BI -ipath " GLOB"
  1380. Case-insensitive version of
  1381. .BR -path .
  1382. .TP
  1383. .BI -iregex " REGEX"
  1384. Case-insensitive version of
  1385. .BR -regex .
  1386.  
  1387. .TP
  1388. .BI -dpath " GLOB"
  1389. Only search down directories whose path matches the given pattern (this
  1390. doesn't apply to the initial directory given by
  1391. .BI -dir ,
  1392. of course).
  1393. Something like
  1394. .nf
  1395.     -dir /usr/man -dpath /usr/man/man*
  1396. .fi
  1397. would completely skip
  1398. "/usr/man/cat1", "/usr/man/cat2", etc.
  1399. .TP
  1400. .BI -dskip " GLOB"
  1401. Skips directories whose name (not path) matches the given pattern.
  1402. Something like
  1403. .nf
  1404.     -dir /usr/man -dskip cat*
  1405. .fi
  1406. would completely skip any directory in the tree whose name begins with "cat"
  1407. (including "/usr/man/cat1", "/usr/man/cat2", etc.).
  1408. .TP
  1409. .BI -dregex " REGEX"
  1410. Like
  1411. .BI -dpath ,
  1412. but the pattern is a full perl regex. Note that this quite different
  1413. from
  1414. .B -regex
  1415. which considers only file names (not paths). This option considers
  1416. full directory paths (not just names). It's much more useful this way.
  1417. Sorry if it's confusing.
  1418. .TP
  1419. .BI -dpath " GLOB"
  1420. This option exists, but is probably not very useful. It probably wants to
  1421. be like the '-below' or something I mention in the "TODO" section.
  1422. .TP
  1423. .BI -idpath " GLOB"
  1424. Case-insensitive version of
  1425. .BR -dpath .
  1426. .TP
  1427. .BI -idskip " GLOB"
  1428. Case-insensitive version of
  1429. .BR -dskip .
  1430. .TP
  1431. .BI -idregex " REGEX"
  1432. Case-insensitive version of
  1433. .BR -dregex .
  1434. .TP
  1435. .B -all
  1436. Ignore any 'magic' or 'option' lines in the startup file.
  1437. The effect is that all files that would otherwise be automatically
  1438. excluded are considered.
  1439. .TP
  1440. .BI -x SPECIAL
  1441. Arguments starting with
  1442. .B -x
  1443. (except
  1444. .BR -xdev ,
  1445. explained elsewhere) do special interaction with the
  1446. .I ~/.search
  1447. startup file. Something like
  1448. .nf
  1449.     -xflag1 -xflag2
  1450. .fi
  1451. will turn on "flag1" and "flag2" in the startup file (and is
  1452. the same as "-xflag1,flag2"). You can use this to write your own
  1453. rules for what kinds of files are to be considered.
  1454.  
  1455. For example, the internal-default startup file contains the line
  1456. .nf
  1457.     <!~> option: -skip '~ #'
  1458. .fi
  1459. This means that if the
  1460. .B -x~
  1461. flag is
  1462. .I not
  1463. seen, the option
  1464. .nf
  1465.     -skip '~ #'
  1466. .fi
  1467. should be done.
  1468. The effect is that emacs temp and backup files are not normally
  1469. considered, but you can included them with the -x~ flag.
  1470.  
  1471. You can write your own rules to customize
  1472. .I search
  1473. in powerful ways. See the STARTUP FILE section below.
  1474. .TP
  1475. .B -why
  1476. Print a message (to stderr) when and why a file is not considered.
  1477.  
  1478. .SH "OPTIONS TELLING WHAT TO DO WITH FILES THAT WILL BE CONSIDERED"
  1479. .TP
  1480. .B -find
  1481. (you can use
  1482. .B -f
  1483. as well).
  1484. This option changes the basic action of
  1485. .IR search .
  1486.  
  1487. Normally, if a file is considered, it is searched
  1488. for the regular expressions as described earlier. However, if this option
  1489. is given, the filename is printed and no searching takes place. This turns
  1490. .I search
  1491. into a 'find' of some sorts.
  1492.  
  1493. In this case, no regular expressions are needed on the command line
  1494. (any that are there are silently ignored).
  1495.  
  1496. This is not intended to be a replacement for the 'find' program,
  1497. but to aid
  1498. you in understanding just what files are getting past the exclusion checks.
  1499. If you really want to use it as a sort of replacement for the 'find' program,
  1500. you might want to use
  1501. .B -all
  1502. so that it doesn't waste time checking to see if the file is binary, etc
  1503. (unless you really want that, of course).
  1504.  
  1505. If you use
  1506. .BR -find ,
  1507. none of the "GREP-LIKE OPTIONS" (below) matter.
  1508.  
  1509. As a replacement for 'find',
  1510. .I search
  1511. is probably a bit slower (or in the case of GNU find, a lot slower --
  1512. GNU find is
  1513. .I unbelievably
  1514. fast).
  1515. However, "search -ffind"
  1516. might be more useful than 'find' when options such as
  1517. .B -skip
  1518. are used (at least until 'find' gets such functionality).
  1519. .TP
  1520. .B -ffind
  1521. (or
  1522. .BR -ff )
  1523. A faster more 'find'-like find. Does
  1524. .nf
  1525.     -find  -all -dorep
  1526. .fi
  1527. .SH "GREP-LIKE OPTIONS"
  1528. These options control how a searched file is accessed,
  1529. and how things are printed.
  1530. .TP
  1531. .B -i
  1532. Ignore letter case when matching.
  1533. .TP
  1534. .B -w
  1535. Consider only whole-word matches ("whole word" as defined by perl's "\\b"
  1536. regex).
  1537. .TP
  1538. .B -u
  1539. If the regex(es) is/are simple, try to modify them so that they'll work
  1540. in manpage-like underlined text (i.e. like _^Ht_^Hh_^Hi_^Hs).
  1541. This is very rudimentary at the moment.
  1542. .TP
  1543. .B -list
  1544. (you can use
  1545. .B -l
  1546. too).
  1547. Don't print matching lines, but the names of files that contain matching
  1548. lines. This will likely be *much* faster, as special optimizations are
  1549. made -- particularly with large files.
  1550. .TP
  1551. .B -n
  1552. Pepfix each line by its line number.
  1553. .TP
  1554. .B -nice
  1555. Not a grep-like option, but similar to
  1556. .BR -list ,
  1557. so included here.
  1558. .B -nice
  1559. will have the output be a bit more human-readable, with matching lines printed
  1560. slightly indented after the filename, a'la
  1561. .nf
  1562.  
  1563.    % search foo
  1564.    somedir/somefile: line with foo in it
  1565.    somedir/somefile: some food for thought
  1566.    anotherdir/x: don't be a buffoon!
  1567.    %
  1568.  
  1569. .fi
  1570. will become
  1571. .nf
  1572.  
  1573.    % search -nice foo
  1574.    somedir/somefile:
  1575.      line with foo in it
  1576.      some food for thought
  1577.    anotherdir/x:
  1578.      don't be a buffoon!
  1579.    %
  1580.  
  1581. .fi
  1582. This option due to Lionel Cons.
  1583. .TP
  1584. .B -nnice
  1585. Be a bit nicer than
  1586. .BR -nice .
  1587. Prefix each file's output by a rule line, and follow with an extra blank line.
  1588. .TP
  1589. .B -h
  1590. Don't prepend each output line with the name of the file
  1591. (meaningless when
  1592. .B -find
  1593. or
  1594. .B -l
  1595. are given).
  1596.  
  1597. .SH "OTHER OPTIONS"
  1598. .TP
  1599. .B -help
  1600. Print the usage information.
  1601. .TP
  1602. .B -version
  1603. Print the version information and quit.
  1604. .TP
  1605. .B -v
  1606. Set the level of message verbosity.
  1607. .B -v
  1608. will print a note whenever a new directory is entered.
  1609. .B -vv
  1610. will also print a note "every so often". This can be useful to see
  1611. what's happening when searching huge directories.
  1612. .B -vvv
  1613. will print a new with every file.
  1614. .B -vvvv
  1615. is
  1616. -vvv
  1617. plus
  1618. .BR -why .
  1619. .TP
  1620. .B -e
  1621. This ends the options, and can be useful if the regex begins with '-'.
  1622. .TP
  1623. .B -showrc
  1624. Shows what is being considered in the startup file, then exits.
  1625. .TP
  1626. .B -dorep
  1627. Normally, an identical file won't be checked twice (even with multiple
  1628. hard or symbolic links). If you're just trying to do a fast
  1629. .BR -find ,
  1630. the bookkeeping to remember which files have been seen is not desirable,
  1631. so you can eliminate the bookkeeping with this flag.
  1632.  
  1633. .SH "STARTUP FILE"
  1634. When
  1635. .I search
  1636. starts up, it processes the directives in
  1637. .IR ~/.search .
  1638. If no such file exists, a default
  1639. internal version is used.
  1640.  
  1641. The internal version looks like:
  1642. .nf
  1643.  
  1644.    magic: 32 : $H =~ m/[\ex00-\ex06\ex10-\ex1a\ex1c-\ex1f\ex80\exff]{2}/
  1645.    option: -skip '.a .COM .elc .EXE .gz .o .pbm .xbm .dvi'
  1646.    option: -iskip '.tarz .zip .z .lzh .jpg .jpeg .gif .uu'
  1647.    <!~> option: -skip '~ #'
  1648.  
  1649. .fi
  1650. If you wish to create your own "~/.search",
  1651. you might consider copying the above, and then working from there.
  1652.  
  1653. There are two kinds of directives in a startup file: "magic" and "option".
  1654. .RS 0n
  1655. .TP
  1656. OPTION
  1657. Option lines will automatically do the command-line options given.
  1658. For example, the line
  1659. .nf
  1660.     option: -v
  1661. .fi
  1662. in you startup file will turn on -v every time, without needing to type it
  1663. on the command line.
  1664.  
  1665. The text on the line after the "option:" directive is processed
  1666. like the Bourne shell, so make sure to pay attention to quoting.
  1667. .nf
  1668.     option: -skip .exe .com
  1669. .fi
  1670. will give an error (".com" by itself isn't a valid option), while
  1671. .nf
  1672.     option: -skip ".exe .com"
  1673. .fi
  1674. will properly include it as part of -skip's argument.
  1675.  
  1676. .TP
  1677. MAGIC
  1678. Magic lines are used to determine if a file should be considered a binary
  1679. or not (the term "magic" refers to checking a file's magic number).  These
  1680. are described in more detail below.
  1681. .RE
  1682.  
  1683. Blank lines and comments (lines beginning with '#') are allowed.
  1684.  
  1685. If a line begins with  <...>, then it's a check to see if the
  1686. directive on the line should be done or not. The stuff inside the <...>
  1687. can contain perl's && (and), || (or), ! (not), and parens for grouping,
  1688. along with "flags" that might be indicated by the user with
  1689. .BI -x flag
  1690. options.
  1691.  
  1692. For example, using "-xfoo" will cause "foo" to be true inside the <...>
  1693. blocks. Therefore, a line beginning with "<foo>" would be done only when
  1694. "-xfoo" had been specified, while a line beginning with "<!foo>" would be
  1695. done only when "-xfoo" is not specified (of course, a line without any <...>
  1696. is done in either case).
  1697.  
  1698. A realistic example might be
  1699. .nf
  1700.     <!v> -vv
  1701. .fi
  1702. This will cause -vv messages to be the default, but allow "-xv" to override.
  1703.  
  1704. There are a few flags that are set automatically:
  1705. .RS
  1706. .TP
  1707. .B TTY
  1708. true if the output is to the screen (as opposed to being redirected to a file).
  1709. You can force this (as with all the other automatic flags) with -xTTY.
  1710. .TP
  1711. .B -v
  1712. True if -v was specified. If -vv was specified, both 
  1713. .B -v
  1714. and
  1715. .B -vv
  1716. flags are true (and so on).
  1717. .TP
  1718. .B -nice
  1719. True if -nice was specified. Same thing about -nnice as for -vv.
  1720. .PP
  1721. .TP
  1722. .B -list
  1723. true if -list (or -l) was given.
  1724. .TP
  1725. .B -dir
  1726. true if -dir was given.
  1727. .RE
  1728.  
  1729. Using this info, you might change the last example to
  1730. .nf
  1731.  
  1732.     <!v && !-v> option: -vv
  1733.  
  1734. .fi
  1735. The added "&& !-v" means "and if the '-v' option not given".
  1736. This will allow you to use "-v" alone on the command line, and not
  1737. have this directive add the more verbose "-vv" automatically.
  1738.  
  1739. .RS 0
  1740. Some other examples:
  1741. .TP
  1742. <!-dir && !here> option: -dir ~/
  1743. Effectively make the default directory your home directory (instead of the
  1744. current directory). Using -dir or -xhere will undo this.
  1745. .TP
  1746. <tex> option: -name .tex -dir ~/pub
  1747. Create '-xtex' to search only "*.tex" files in your ~/pub directory tree.
  1748. Actually, this could be made a bit better. If you combine '-xtex' and '-dir'
  1749. on the command line, this directive will add ~/pub to the list, when you
  1750. probably want to use the -dir directory only. You could do
  1751. .nf
  1752.  
  1753.    <tex> option: -name .tex
  1754.    <tex && !-dir> option: -dir ~/pub
  1755. .fi
  1756.  
  1757. to will allow '-xtex' to work as before, but allow a command-line "-dir"
  1758. to take precedence with respect to ~/pub.
  1759. .TP
  1760. <fluff> option: -nnice -sort -i -vvv
  1761. Combine a few user-friendly options into one '-xfluff' option.
  1762. .TP
  1763. <man> option: -ddir /usr/man -v -w
  1764. When the '-xman' option is given, search "/usr/man" for whole-words
  1765. (of whatever regex or regexes are given on the command line), with -v.
  1766. .RE
  1767.  
  1768. The lines in the startup file are executed from top to bottom, so something
  1769. like
  1770. .nf
  1771.  
  1772.    <both> option: -xflag1 -xflag2
  1773.    <flag1> option: ...whatever...
  1774.    <flag2> option: ...whatever...
  1775.  
  1776. .fi
  1777. will allow '-xboth' to be the same as '-xflag1 -xflag2' (or '-xflag1,flag2'
  1778. for that matter). However, if you put the "<both>" line below the others,
  1779. they will not be true when encountered, so the result would be different
  1780. (and probably undesired).
  1781.  
  1782. The "magic" directives are used to determine if a file looks to be binary
  1783. or not. The form of a magic line is
  1784. .nf
  1785.     magic: \fISIZE\fP : \fIPERLCODE\fP
  1786. .fi
  1787. where
  1788. .I SIZE
  1789. is the number of bytes of the file you need to check, and
  1790. .I PERLCODE
  1791. is the code to do the check. Within
  1792. .IR PERLCODE ,
  1793. the variable $H will hold at least the first
  1794. .I SIZE
  1795. bytes of the file (unless the file is shorter than that, of course).
  1796. It might hold more bytes. The perl should evaluate to true if the file
  1797. should be considered a binary.
  1798.  
  1799. An example might be
  1800. .nf
  1801.     magic: 6 : substr($H, 0, 6) eq 'GIF87a'
  1802. .fi
  1803. to test for a GIF ("-iskip .gif" is better, but this might be useful
  1804. if you have images in files without the ".gif" extension).
  1805.  
  1806. Since the startup file is checked from top to bottom, you can be a bit
  1807. efficient:
  1808. .nf
  1809.     magic: 6 : ($x6 = substr($H, 0, 6)) eq 'GIF87a'
  1810.     magic: 6 :  $x6                     eq 'GIF89a'
  1811. .fi
  1812. You could also write the same thing as
  1813. .nf
  1814.   magic: 6 : (($x6 = substr($H, 0, 6)) eq 'GIF87a') || ## an old gif, or.. \e
  1815.            $x6                     eq 'GIF89a'     ## .. a new one.
  1816. .fi
  1817. since newlines may be escaped.
  1818.  
  1819. The default internal startup file includes
  1820. .nf
  1821.    magic: 32 : $H =~ m/[\ex00-\ex06\ex10-\ex1a\ex1c-\ex1f\ex80\exff]{2}/
  1822. .fi
  1823. which checks for certain non-printable characters, and catches a large
  1824. number of binary files, including most system's executables, linkable
  1825. objects, compressed, tarred, and otherwise folded, spindled, and mutilated
  1826. files.
  1827.  
  1828. Another example might be
  1829. .nf
  1830.     ## an archive library
  1831.     magic: 17 : substr($H, 0, 17) eq "!<arch>\en__.SYMDEF"
  1832. .fi
  1833.  
  1834. .SH "RETURN VALUE"
  1835. .I Search
  1836. returns zero if lines (or files, if appropriate) were found,
  1837. or if no work was requested (such as with
  1838. .BR -help ).
  1839. Returns 1 if no lines (or files) were found.
  1840. Returns 2 on error.
  1841.  
  1842. .SH TODO
  1843. Things I'd like to add some day:
  1844. .nf
  1845.   + show surrounding lines (context).
  1846.   + highlight matched portions of lines.
  1847.   + add '-and', which can go between regexes to override
  1848.     the default logical or of the regexes.
  1849.   + add something like
  1850.       -below GLOB
  1851.     which will examine a tree and only consider files that
  1852.     lie in a directory deeper than one named by the pattern.
  1853.   + add 'warning' and 'error' directives.
  1854.   + add 'help' directive.
  1855. .fi
  1856. .SH BUGS
  1857. If -xdev and multiple -dir arguments are given, any file in any of the
  1858. target filesystems are allowed. It would be better to allow each filesystem
  1859. for each separate tree.
  1860.  
  1861. Multiple -dir args might also cause some confusing effects. Doing
  1862. .nf
  1863.    -dir some/dir -dir other
  1864. .fi
  1865. will search "some/dir" completely, then search "other" completely. This
  1866. is good. However, something like
  1867. .nf
  1868.    -dir some/dir -dir some/dir/more/specific
  1869. .fi
  1870. will search "some/dir" completely *except for* "some/dir/more/specific",
  1871. after which it will return and be searched. Not really a bug, but just sort
  1872. of odd.
  1873.  
  1874. File times (for -newer, etc.) of symbolic links are for the file, not the
  1875. link. This could cause some misunderstandings.
  1876.  
  1877. Probably more. Please let me know.
  1878. .SH AUTHOR
  1879. Jeffrey Friedl, Omron Corp (jfriedl@omron.co.jp)
  1880. .br
  1881. http://www.wg.omron.co.jp/cgi-bin/j-e/jfriedl.html
  1882.  
  1883. .SH "LATEST SOURCE"
  1884. See http://www.wg.omron.co.jp/~jfriedl/perl/index.html
  1885.  
  1886. __END__
  1887. :endofperl
  1888.